<?php
/*
 * @Description    : 文件上传
 * @Author         : QianLong
 * @Date           : 2023-01-11 12:13:55
 * @LastEditors    : QianLong
 * @Site           : http://21ds.cn
 * @LastEditTime   : 2023-10-14 11:35:49
 */

declare(strict_types=1);

namespace App\Controller;

use App\Common\RedisCache;
use App\Constants\Status;
use App\Exception\ApiException;
use App\Job\SignFailAddJob;
use App\Service\File\AliOss;
use App\Service\File\Qiniu;
use App\Service\File\TenCos;
use Qianlong\Validate\Validate;

class FileController extends AbstractController
{
  public function upload(\League\Flysystem\Filesystem $filesystem)
  {
    $valitor = new Validate();
    $valitor->addColumn('fs_id')->required();
    $valitor->addColumn('fc_id')->required();
    $valitor->addColumn('same_ignore')->optional();
    $valitor->addColumn('fsi_id')->optional();
    if ($valitor && !$this->validate($valitor)) {
      throw new ApiException(Status::CODE_BAD_REQUEST, $valitor->getError()->__toString());
    }
    unset($valitor);
    $param = $this->request->all();
    $file = $this->request->file('file');

    $userInfo = $this->dataResource->getUserInfo();
    $redisCache = new RedisCache;
    $pushSetting = $redisCache->getFileSetting($userInfo['uid']);
    if ($pushSetting['ip_limit'] == 1 && !empty($pushSetting['server_ip'])) {
      $remoteIp = $this->dataResource->getClientIp($this->request);
      $sysSetting = $redisCache->getSysSetting();
      $allIp = $sysSetting['server_ip'].','. $pushSetting['server_ip'];
      $server_ip = explode(',', $allIp);
      $is_local = filter_var($remoteIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
      if (!in_array($remoteIp, $server_ip) && $is_local != false) {
        return $this->response->json(Status::CODE_FAIL, 'IP不在可信范围内', []);
      }
    }
    $commonService = new \App\Service\Common;
    $serverInfo = $redisCache->getFileServer($param['fs_id']);
    if (isset($param['fsi_id'])&&!empty($param['fsi_id'])) {
      $serverInfoFeedback = $redisCache->getFeedbackSite($param['fsi_id']);
      $newSign2 = $commonService->generateSignature($param, md5($serverInfoFeedback['server_secret']));
      if ($param['sign'] != $newSign2['sign']) {
        $logData['url'] = $this->request->fullUrl();
        $logData['remoteIp'] = $this->dataResource->getClientIp($this->request);
        $logData['user_sign'] = $param['sign'];
        $logData['uid'] = $serverInfoFeedback['uid'];
        $logData['server_sign'] = $newSign2['sign'];
        $logData['server_query'] = $newSign2['query'];
        queue_push(new SignFailAddJob($logData));
        return $this->response->json(Status::CODE_FAIL, 'sign签名校验失败f');
      }
    }else{
      $newSign = $commonService->devSignGeneral($param, $serverInfo['server_secret']);
      $newSign2 = $commonService->generateSignature($param, $serverInfo['server_secret']);
      if ($param['sign'] != $newSign && $param['sign'] != $newSign2['sign']) {
        $logData['url'] = $this->request->fullUrl();
        $logData['remoteIp'] = $this->dataResource->getClientIp($this->request);
        $logData['user_sign'] = $param['sign'];
        $logData['uid'] = $serverInfo['uid'];
        $logData['server_sign'] = $newSign2['sign'];
        $logData['server_query'] = $newSign2['query'];
        queue_push(new SignFailAddJob($logData));
        return $this->response->json(Status::CODE_FAIL, 'sign签名校验失败');
      }
    }
    if ($serverInfo['status'] != 1) {
      return $this->response->json(Status::CODE_FAIL, '当前配置状态不可用，如需使用，请登录柠聚开发平台启用后重试', []);
    }
    if (isset($serverInfo['ak_from']) && $serverInfo['ak_from'] == 'platform' && isset($serverInfo['ak_id']) && !empty($serverInfo['ak_id'])) {
      $akInfo = $this->redisCache->getAk($serverInfo['ak_id'], $serverInfo['uid']);
      unset($akInfo['_id'], $akInfo['platform']);
      $serverInfo = array_merge($serverInfo, $akInfo);
      unset($akInfo);
    }
    $cateInfo = $redisCache->getFileCate($param['fc_id']);
    $fc_path = (isset($cateInfo['tag']) && !empty($cateInfo['tag']))? $cateInfo['tag']: $cateInfo['_id'];
    $return['file_id'] = $fileData['_id'] = createULId();
    $fileData['fs_id'] = $param['fs_id'];
    $fileData['fc_id'] = $param['fc_id'];
    $fileData['uid'] = (int)$userInfo['uid'];
    $fileData['username'] = $userInfo['username'];
    $fileData['aliyun_bucket'] = isset($serverInfo['aliyun_bucket'])? $serverInfo['aliyun_bucket']:'';
    $fileData['aliyun_region'] = isset($serverInfo['aliyun_region'])? $serverInfo['aliyun_region']:'';
    $fileData['aliyun_stylename'] = isset($serverInfo['aliyun_stylename'])? $serverInfo['aliyun_stylename']:'';
    $fileData['tenc_bucket'] = isset($serverInfo['tenc_bucket'])? $serverInfo['tenc_bucket']:'';
    $fileData['tenc_region'] = isset($serverInfo['tenc_region'])? $serverInfo['tenc_region']:'';
    $fileData['qiniu_bucket'] = isset($serverInfo['qiniu_bucket'])? $serverInfo['qiniu_bucket']:'';
    $fileData['qiniu_region'] = isset($serverInfo['qiniu_region'])? $serverInfo['qiniu_region']:'';
    $fileData['platform'] = $serverInfo['platform'];
    $fileData['name'] = $file->getClientFilename();
    $fileData['ext'] = strtolower($file->getExtension());
    $fileData['size_byte'] = $file->getSize();
    $fileData['size_mb'] = round($fileData['size_byte'] / 1048576,3);
    $fileData['size_kb'] = round($fileData['size_byte'] / 1024,3);
    $fileData['create_time'] = time();
    $fileData['is_use'] = 0;
    $fileData['use_url'] = '';
    $stream = fopen($file->getRealPath(), 'r+');
    $filePath = $fc_path.'/'.$fileData['_id'] . '.' . $fileData['ext'];
    $filesystem->writeStream(
      '/'.$filePath,
      $stream
    );
    fclose($stream);
    $fileData['file_md5'] = md5_file(BASE_PATH . '/runtime/' . $filePath);
    if (isset($param['same_ignore']) && $param['same_ignore'] == 1) {
      $hasFile = mongodb2()->file_list->findOne(['file_md5' => $fileData['file_md5'], 'uid' => $fileData['uid']]);
      $hasFile = json_decode(json_encode($hasFile), true);
      if (!empty($hasFile)) {
        $return['file_id'] = $hasFile['_id'];
        $return['url'] = $hasFile['url'];
        $filesystem->delete('/' . $filePath);
        return $this->response->json(Status::FILE_EXIST, '文件已存在', $return);
      }
    }
    if ($serverInfo['platform'] == 'aliyun_oss') {
      $ossServer = new AliOss($serverInfo);
      $uploadInfo = $ossServer->uploadFile($filePath, BASE_PATH . '/runtime/'. $filePath);
      $fileData['object'] = $filePath;
      $fileData['oss_url'] = $uploadInfo['oss-request-url'];
      $return['url'] = $fileData['url'] = $ossServer->getOssUrl($fileData['object']);
      if (!empty($fileData['aliyun_stylename']) && in_array($fileData['ext'],['png','jpg','jpeg','webp','bmp'])) {
        $return['url'] = $return['url']. '?x-oss-process=style/'. $fileData['aliyun_stylename'];
      }
    }else if ($serverInfo['platform'] == 'tencent_cos') {
      $ossServer = new TenCos($serverInfo);
      $uploadInfo = $ossServer->uploadFile($filePath, BASE_PATH . '/runtime/'. $filePath);
      $fileData['object'] = $filePath;
      $fileData['oss_url'] = '';
      $return['url'] = $fileData['url'] = $ossServer->getOssUrl($fileData['object']);
    }else if ($serverInfo['platform'] == 'qiniu') {
      $ossServer = new Qiniu($serverInfo);
      $uploadInfo = $ossServer->uploadFile($filePath, BASE_PATH . '/runtime/'. $filePath, $fileData['name']);
      $fileData['object'] = $filePath;
      $fileData['oss_url'] = '';
      $return['url'] = $fileData['url'] = $ossServer->getUrl($fileData['object']);
    }
    $filesystem->delete('/' . $filePath);
      $fileData['date'] = date('Ymd');
      $fileData['hour'] = date('YmdH');
      $fileData['only_hour'] = date('H') . ':00';
      $fileData['hour_stamp'] = strtotime(date('Y-m-d H') . ':00:00');
      $fileData['month'] = date('Ym');
      $fileData['year'] = date('Y');
      mongodb2()->file_list->insertOne($fileData);
    return $this->response->json(Status::CODE_OK, 'success', $return);
  }
  public function deleteFile()
  {
    $valitor = new Validate();
    $valitor->addColumn('file_id')->optional();
    $valitor->addColumn('file_url')->optional();
    if ($valitor && !$this->validate($valitor)) {
      throw new ApiException(Status::CODE_BAD_REQUEST, $valitor->getError()->__toString());
    }
    unset($valitor);
    $param = $this->request->all();
    $userInfo = $this->dataResource->getUserInfo();
    $redisCache = new RedisCache;
    $pushSetting = $redisCache->getFileSetting($userInfo['uid']);
    if ($pushSetting['ip_limit'] == 1 && !empty($pushSetting['server_ip'])) {
      $remoteIp = $this->dataResource->getClientIp($this->request);
      $sysSetting = $redisCache->getSysSetting();
      $allIp = $sysSetting['server_ip'] . ',' . $pushSetting['server_ip'];
      $server_ip = explode(',', $allIp);
      $is_local = filter_var($remoteIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
      if (!in_array($remoteIp, $server_ip) && $is_local != false) {
        return $this->response->json(Status::CODE_FAIL, 'IP不在可信范围内', []);
      }
    }
    $serverInfo = $redisCache->getFileServer($param['fs_id']);
    $newSign = (new \App\Service\Common)->devSignGeneral($param, $serverInfo['server_secret']);
    $newSign2 = (new \App\Service\Common)->generateSignature($param, $serverInfo['server_secret']);
    if ($param['sign'] != $newSign && $param['sign'] != $newSign2['sign']) {
      $logData['url'] = $this->request->fullUrl();
      $logData['remoteIp'] = $remoteIp;
      $logData['user_sign'] = $param['sign'];
      $logData['server_sign'] = $newSign2['sign'];
      $logData['server_query'] = $newSign2['query'];
      $logData['uid'] = $serverInfo['uid'];
      queue_push(new SignFailAddJob($logData));
      return $this->response->json(Status::CODE_FAIL, 'sign签名校验失败');
    }
    if ($serverInfo['status'] != 1) {
      return $this->response->json(Status::CODE_FAIL, '当前配置状态不可用，如需使用，请登录柠聚开发平台启用后重试', []);
    }
    if (empty($param['file_id']) && empty($param['file_url'])) {
      return $this->response->json(Status::CODE_FAIL, 'file_id及file_url不能都为空', []);
    }
    if (isset($serverInfo['ak_from']) && $serverInfo['ak_from'] == 'platform' && isset($serverInfo['ak_id']) && !empty($serverInfo['ak_id'])) {
      $akInfo = $this->redisCache->getAk($serverInfo['ak_id'], (int)$userInfo['uid']);
      unset($akInfo['_id']);
      $serverInfo = array_merge($serverInfo, $akInfo);
      unset($akInfo);
    }
    $where = [];
    if (!empty($param['file_id'])) {
      $where['_id']['$in'] = explode(',', $param['file_id']);
      $where['uid'] = (int)$userInfo['uid'];
      $hasLog = mongodb2()->file_list->find($where);
      if (!empty($hasLog)) {
        foreach ($hasLog as $key => $vo) {
          if ($vo['platform'] == 'aliyun_oss') {
            (new AliOss($serverInfo))->deleteOssFile($vo['object'], $vo['aliyun_bucket']);
          } elseif ($vo['platform'] == 'tencent_cos') {
            (new TenCos($serverInfo))->deleteOssFile($vo['object'], $vo['tenc_bucket']);
          } elseif ($vo['platform'] == 'qiniu') {
            (new Qiniu($serverInfo))->deleteFile($vo['object'], $vo['qiniu_bucket'], $vo['qiniu_region']);
          }
        }
      }
    }
    if (!empty($param['file_url'])) {
      $file_url_list = explode(',', $param['file_url']);
      $pathArr = [];
      foreach ($file_url_list as $url) {
        $parseUrl = parse_url($url);
        $path = $parseUrl['path'];
        if (isset($path) && !empty($path) && !in_array($path,$pathArr)) {
          $pathArr[] = ltrim($path,'/');
        }
      }
      if (!empty($pathArr)) {
        $where['object']['$in'] = $pathArr;
        $where['uid'] = (int)$userInfo['uid'];
        $hasLog = mongodb2()->file_list->find($where);
        if (!empty($hasLog)) {
          foreach ($hasLog as $key => $vo) {
            if ($vo['platform'] == 'aliyun_oss') {
              (new AliOss($serverInfo))->deleteOssFile($vo['object'], $vo['aliyun_bucket']);
            } elseif ($vo['platform'] == 'tencent_cos') {
              (new TenCos($serverInfo))->deleteOssFile($vo['object'], $vo['tenc_bucket']);
            } elseif ($vo['platform'] == 'qiniu') {
              (new Qiniu($serverInfo))->deleteFile($vo['object'], $vo['qiniu_bucket'], $vo['qiniu_region']);
            }
          }
        }
      }
    }
    if (!empty($where)) {
      mongodb2()->file_list->deleteMany($where);
    }
    return $this->response->json(Status::CODE_OK, 'success', '');
  }
  public function getFileUrl()
  {
    $valitor = new Validate();
    $valitor->addColumn('file_id')->optional();
    if ($valitor && !$this->validate($valitor)) {
      throw new ApiException(Status::CODE_BAD_REQUEST, $valitor->getError()->__toString());
    }
    unset($valitor);
    $param = $this->request->all();
    $userInfo = $this->dataResource->getUserInfo();
    $redisCache = new RedisCache;
    $pushSetting = $redisCache->getFileSetting($userInfo['uid']);
    if ($pushSetting['ip_limit'] == 1 && !empty($pushSetting['server_ip'])) {
      $remoteIp = $this->dataResource->getClientIp($this->request);
      $sysSetting = $redisCache->getSysSetting();
      $allIp = $sysSetting['server_ip'] . ',' . $pushSetting['server_ip'];
      $server_ip = explode(',', $allIp);
      $is_local = filter_var($remoteIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
      if (!in_array($remoteIp, $server_ip) && $is_local != false) {
        return $this->response->json(Status::CODE_FAIL, 'IP不在可信范围内', []);
      }
    }
    $serverInfo = $redisCache->getFileServer($param['fs_id']);
    $newSign = (new \App\Service\Common)->devSignGeneral($param, $serverInfo['server_secret']);
    $newSign2 = (new \App\Service\Common)->generateSignature($param, $serverInfo['server_secret']);
    if ($param['sign'] != $newSign && $param['sign'] != $newSign2['sign']) {
      $logData['url'] = $this->request->fullUrl();
      $logData['remoteIp'] = $remoteIp;
      $logData['user_sign'] = $param['sign'];
      $logData['server_sign'] = $newSign2['sign'];
      $logData['server_query'] = $newSign2['query'];
      $logData['uid'] = $serverInfo['uid'];
      queue_push(new SignFailAddJob($logData));
      return $this->response->json(Status::CODE_FAIL, 'sign签名校验失败');
    }
    if ($serverInfo['status'] != 1) {
      return $this->response->json(Status::CODE_FAIL, '当前配置状态不可用，如需使用，请登录柠聚开发平台启用后重试', []);
    }
    if (empty($param['file_id']) && empty($param['file_url'])) {
      return $this->response->json(Status::CODE_FAIL, 'file_id及file_url不能都为空', []);
    }
    if (isset($serverInfo['ak_from']) && $serverInfo['ak_from'] == 'platform' && isset($serverInfo['ak_id']) && !empty($serverInfo['ak_id'])) {
      $akInfo = $this->redisCache->getAk($serverInfo['ak_id'], (int)$userInfo['uid']);
      unset($akInfo['_id']);
      $serverInfo = array_merge($serverInfo, $akInfo);
      unset($akInfo);
    }
    $where = [];
    $fileList = [];
    if (!empty($param['file_id'])) {
      $where['_id']['$in'] = explode(',', $param['file_id']);
      $where['uid'] = (int)$userInfo['uid'];
      $hasLog = mongodb2()->file_list->find($where);
      if (!empty($hasLog)) {
        foreach ($hasLog as $key => $vo) {
          if ($vo['platform'] == 'aliyun_oss') {
            $fileList[] = (new AliOss($serverInfo))->getFileUrl($vo['object']);
          } elseif ($vo['platform'] == 'tencent_cos') {
            $fileList[] = (new TenCos($serverInfo))->getFileUrl($vo['object']);
          } elseif ($vo['platform'] == 'qiniu') {
            $fileList[] = (new Qiniu($serverInfo))->getUrl($vo['object']);
          }
        }
      }
    }
    if (!empty($param['file_url'])) {
      $file_url_list = explode(',', $param['file_url']);
      $pathArr = [];
      foreach ($file_url_list as $url) {
        $parseUrl = parse_url($url);
        $path = $parseUrl['path'];
        if (isset($path) && !empty($path) && !in_array($path,$pathArr)) {
          $pathArr[] = ltrim($path,'/');
        }
      }
      if (!empty($pathArr)) {
        $where['object']['$in'] = $pathArr;
        $where['uid'] = (int)$userInfo['uid'];
        $hasLog = mongodb2()->file_list->find($where);
        if (!empty($hasLog)) {
          foreach ($hasLog as $key => $vo) {
            if ($vo['platform'] == 'aliyun_oss') {
              $fileList[] = (new AliOss($serverInfo))->getFileUrl($vo['object']);
            } elseif ($vo['platform'] == 'tencent_cos') {
              $fileList[] = (new TenCos($serverInfo))->getFileUrl($vo['object']);
            } elseif ($vo['platform'] == 'qiniu') {
              $fileList[] = (new Qiniu($serverInfo))->getUrl($vo['object']);
            }
          }
        }
      }
    }
    return $this->response->json(Status::CODE_OK, 'success', $fileList);
  }
}
